#include "../1km/bsp/can_controller.h"
#include "board.h"
#include "aos/list.h"
#include "stdio.h"
#include "string.h"


// 相关定义
/************************************************************************/
#define TX_QUEUE_DEEP                   (10)
#define RX_MESSAGE_BOX_OFFSET           (1)
#define MAX_RX_MESSAGE_BOX_NUM          (30)
#define TX_MESSAGE_BOX_OFFSET           (RX_MESSAGE_BOX_OFFSET + MAX_RX_MESSAGE_BOX_NUM + 1)
#define MAX_TX_MESSAGE_BOX_NUM          (10)
/* Select 80M clock divided by USB1 PLL (480 MHz) as master flexcan clock source */
#define FLEXCAN_CLOCK_SOURCE_SELECT     (2U)
/* Clock divider for master flexcan clock source */
#define FLEXCAN_CLOCK_SOURCE_DIVIDER    (3U)
/* Get frequency of flexcan clock */
#define CAN_CLK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 6) / (FLEXCAN_CLOCK_SOURCE_DIVIDER + 1U))
/* To consider the First valid MB must be used as Reserved TX MB for ERR005829
   If RX FIFO enable(RFEN bit in MCE set as 1) and RFFN in CTRL2 is set default zero, the first valid TX MB Number is 8
   If RX FIFO enable(RFEN bit in MCE set as 1) and RFFN in CTRL2 is set by other value(0x1~0xF), User should consider
   detail first valid MB number
   If RX FIFO disable(RFEN bit in MCE set as 0) , the first valid MB number is zero */
/*! @brief FlexCAN Rx Message Buffer Mask helper macro. */
#define MAKE_MASK(id, rtr, ide)                                   \
    (((uint32_t)((uint32_t)(rtr) << 31) | (uint32_t)((uint32_t)(ide) << 30)) | \
     FLEXCAN_ID_STD(id)) /*!< Standard Rx Message Buffer Mask helper macro. */


typedef struct {
    uint32_t id;
    uint32_t mask;
} can_filter_t;

typedef struct{
    slist_t                 next;           //链表next
    uint8_t                 rxMb;           //接收邮箱序号
    can_filter_t            filter;         //ID过滤结构
    aos_queue_t             *rx_queue;      //CAN接收队列
    flexcan_mb_transfer_t   mb_rx_transfer; //邮箱传输结构
} rx_node_t;

typedef struct{
    bool                    is_init;        //是否已初始化
    char*                   threadName[30]; //线程名称
    CAN_Type                *pCANx;         //CAN端口
    uint32_t                baudRate;       //can波特率
    slist_t                 list_Mb;        //邮箱列表
    aos_mutex_t             mutex;          //HAL操作互斥锁
    flexcan_handle_t        flexcanHandle;  //fsl层用到的结构
} can_controller_t;


/*在这里对使用到的 CAN 端口进行配置,用户层的 port_id 来源于此序号*/
static can_controller_t can_ctrl[] = {
    [0] ={
        .is_init = false,
        .pCANx = CAN2,
        .baudRate = 250000U,
    },

    // 由于CAN1 目前通过canopen连接着IO子板，canopen中已经初始化了，废除前这里仅列出CAN2
    // [1] ={
    //     .pCANx = CAN1,
    //     .baudRate = 1000000U,
    // },
};

uint32_t g_tx_cnts = 0;
uint32_t g_tx_fail_cnts = 0;

// 内部函数声明
/************************************************************************/
static bool _can_controller_byId(can_controller_t * const pCan_ctrl);
static int8_t _get_free_rx_mb(CAN_Type *pCANx);
static uint8_t _get_rx_mb_remaining_nums(CAN_Type *pCANx);
static can_controller_t *_get_can_controller_handler_byId(uint8_t port_id);
static bool _can_control_send(uint8_t port_id, flexcan_frame_t * const pFrame);
static void _flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData);

void modify_can_cantroller_bitrate(uint8_t port_id, uint32_t baudRate)
{
    can_controller_t *pCan_ctrl = _get_can_controller_handler_byId(port_id);
    pCan_ctrl->baudRate = baudRate;
}
void get_bus_error_cnt(uint8_t port_id, uint8_t *txErrBuf, uint8_t *rxErrBuf, uint32_t *tx_fail_cnts, uint16_t *tx_fail_rate)
{
    can_controller_t *pCan_ctrl = _get_can_controller_handler_byId(port_id);
    FLEXCAN_GetBusErrCount(pCan_ctrl->pCANx, txErrBuf, rxErrBuf);
    *tx_fail_cnts = g_tx_fail_cnts;
    *tx_fail_rate = g_tx_fail_cnts*100/g_tx_cnts;
}

bool isFlexCanRxOverflow = false;

bool get_flexcan_rx_overflow(void)
{
    return isFlexCanRxOverflow;
}

// 外部函数
/************************************************************************/
/**
 * @brief       初始化 CAN 列表中所列CAN接口
 * @return      bool                是否初始化成功
 */
bool can_controller_init(void)
{
    for (uint8_t i = 0; i < sizeof(can_ctrl) / sizeof(can_controller_t); i++) {
        if (!_can_controller_byId(&can_ctrl[i])){
            return false;
        }
    }
    return true;
}
/**
 * @brief       初始化指定配置的CAN接口（内部函数）
 * @param[in]	pCan_ctrl           配置handle
 * @return      bool                执行结果
 */
static bool _can_controller_byId(can_controller_t * const pCan_ctrl)
{
    CHECK_NULL(pCan_ctrl, "arg null", err_1);

    if (pCan_ctrl->is_init){
        return true;
    }

    flexcan_config_t flexcanConfig;

    /*Clock setting for FLEXCAN*/
    CLOCK_SetMux(kCLOCK_CanMux, FLEXCAN_CLOCK_SOURCE_SELECT);
    CLOCK_SetDiv(kCLOCK_CanDiv, FLEXCAN_CLOCK_SOURCE_DIVIDER);
    /* Get FlexCAN module default Configuration. */
    /*
    * flexcanConfig.clkSrc = kFLEXCAN_ClkSrcOsc;
    * flexcanConfig.baudRate = 1000000U;
    * flexcanConfig.baudRateFD = 2000000U;
    * flexcanConfig.maxMbNum = 16;
    * flexcanConfig.enableLoopBack = false;
    * flexcanConfig.enableSelfWakeup = false;
    * flexcanConfig.enableIndividMask = false;
    * flexcanConfig.enableDoze = false;
    * flexcanConfig.timingConfig = timingConfig;
    */
    FLEXCAN_GetDefaultConfig(&flexcanConfig);

    flexcanConfig.baudRate = pCan_ctrl->baudRate;
    flexcanConfig.maxMbNum = 1 + MAX_RX_MESSAGE_BOX_NUM + MAX_TX_MESSAGE_BOX_NUM;
    flexcanConfig.enableIndividMask = true;     //使用每个邮箱自己的过滤器

    /* Init FlexCAN module. */
#if (!defined(FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE)) || !FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE
        flexcanConfig.clkSrc = kFLEXCAN_ClkSrcPeri;
#endif

    FLEXCAN_Init(pCan_ctrl->pCANx, &flexcanConfig, CAN_CLK_FREQ);

    /* Create FlexCAN handle structure and set call back function. */
    FLEXCAN_TransferCreateHandle(pCan_ctrl->pCANx, &pCan_ctrl->flexcanHandle, _flexcan_callback, pCan_ctrl);

    /************************************************************************/
    //创建用于修改配置时所用的互斥锁
    CHECK_NZERO(aos_mutex_new(&pCan_ctrl->mutex), "creat mutex failed", err_1);
    /************************************************************************/
    pCan_ctrl->is_init = true;
    return true;
err_1:
    return false;
}
/**
 * @brief       添加接收节点（指定过滤器，指定消息接收队列）
 * @param[in]	port_id             can 端口索引 ID
 * @param[in]	node_id             接收节点 ID
 * @param[in]	fit_id              过滤器 ID
 * @param[in]	fit_mask            过滤器屏蔽位
 * @param[in]	queue               消息接收队列
 * @return      bool                执行结果
 */
bool can_controller_add_node_filter_static(uint8_t port_id, uint32_t node_id, uint32_t fit_id, uint32_t fit_mask, aos_queue_t* const queue)
{
    can_controller_t *pCan_ctrl = _get_can_controller_handler_byId(port_id);
    CHECK_NULL(pCan_ctrl, "port_id error", err_1);

    CHECK_NZERO(aos_mutex_lock(&pCan_ctrl->mutex, 100), "get mutex failed", err_1);
    /****************************************************************************************************************/
    // 检测是否有可用的消息邮箱
    CHECK_ERR(_get_rx_mb_remaining_nums(pCan_ctrl->pCANx) > 0, "not RxMB Remaining", err_1);

    // 创建接收节点
    rx_node_t *pNode = aos_malloc(sizeof(rx_node_t));
    CHECK_NULL(pNode, "pNode malloc error", err_1);

    pNode->rx_queue = queue;
    
    // 创建接收帧缓存
    CHECK_NULL(pNode->mb_rx_transfer.frame = aos_malloc(sizeof(flexcan_frame_t)), "pQueueMem malloc error", err_2);

    pNode->rxMb         = _get_free_rx_mb(pCan_ctrl->pCANx);    //获取可用的接收消息邮箱
    pNode->filter.id    = fit_id;
    pNode->filter.mask  = fit_mask;
    pNode->mb_rx_transfer.mbIdx = pNode->rxMb;
    slist_add_tail(&pNode->next, &pCan_ctrl->list_Mb);

    /* Set Rx Masking mechanism. */
    FLEXCAN_SetRxIndividualMask(pCan_ctrl->pCANx, pNode->rxMb, pNode->filter.mask);
    /* Setup Rx Message Buffer. */
    flexcan_rx_mb_config_t mbConfig;
    mbConfig.format     = kFLEXCAN_FrameFormatStandard;
    mbConfig.type       = kFLEXCAN_FrameTypeData;
    mbConfig.id         = FLEXCAN_ID_STD(node_id);
    FLEXCAN_SetRxMbConfig(pCan_ctrl->pCANx, pNode->rxMb, &mbConfig, true);
    FLEXCAN_TransferReceiveNonBlocking(pCan_ctrl->pCANx, &pCan_ctrl->flexcanHandle, &pNode->mb_rx_transfer);
    /****************************************************************************************************************/
    aos_mutex_unlock(&pCan_ctrl->mutex);

    return true;
err_2:
    aos_free(pNode);
err_1:
    return false;
}
/**
 * @brief       添加接收节点（指定消息接收队列）
 * @param[in]	port_id             can 端口索引 ID
 * @param[in]	node_id             接收节点 ID
 * @param[in]	queue               消息接收队列
 * @return      bool                执行结果
 */
bool can_controller_add_node_static(uint8_t port_id, uint32_t node_id, aos_queue_t* const queue)
{
    return can_controller_add_node_filter_static(port_id, node_id, FLEXCAN_ID_STD(node_id), MAKE_MASK(node_id, 0, 0), queue);
}
/**
 * @brief       添加接收节点
 * @param[in]	port_id             can 端口索引 ID
 * @param[in]	node_id             接收节点 ID
 * @param[in]	queue_depth         消息接收队列深度
 * @return      aos_queue_t*        消息接收队列 handle
 */
aos_queue_t* can_controller_add_node(uint8_t port_id, uint32_t node_id, uint8_t queue_depth)
{
    // 创建指定深度的数据接收队列
    void *pQueueMem = aos_malloc(sizeof(flexcan_frame_t) * queue_depth);
    CHECK_NULL(pQueueMem, "pQueueMem malloc error", err_1);

    aos_queue_t *rx_queue = aos_malloc(sizeof(aos_queue_t));
	CHECK_NZERO(aos_queue_new(rx_queue, pQueueMem , sizeof(flexcan_frame_t) * queue_depth, sizeof(flexcan_frame_t)), "queue creat failed", err_2);

    CHECK_ERR(can_controller_add_node_static(port_id, node_id, rx_queue), "add node failed", err_3);

    return rx_queue;
err_3:
    aos_queue_free(rx_queue);
    if (rx_queue){
        aos_free(rx_queue);
    }
err_2:
    aos_free(pQueueMem);
err_1:
    return NULL;
}
/**
 * @brief       通过节点id删除之前注册关联的所有消息邮箱,这些邮箱将被释放以作它用
 * @param[in]	port_id             can 端口索引 ID
 * @param[in]	node_id             接收节点 ID
 * @return      bool                执行结果
 */
bool can_controller_del_node_byId(uint8_t port_id, uint32_t node_id)
{
    can_controller_t *pCan_ctrl = _get_can_controller_handler_byId(port_id);
    CHECK_NULL(pCan_ctrl, "port_id error", err_1);

    rx_node_t *pNode = NULL;
	slist_t *cur = NULL;

    CHECK_NZERO(aos_mutex_lock(&pCan_ctrl->mutex, 100), "get mutex failed", err_1);
    /****************************************************************************************************************/
    //遍历链表找出符合匹配规则的节点,然后删除
    slist_for_each_entry_safe(&pCan_ctrl->list_Mb, cur, pNode, rx_node_t, next) {
        if (pNode->filter.id == node_id){
            slist_del(&pNode->next, &pCan_ctrl->list_Mb);                      //删除链表节点
            FLEXCAN_SetRxMbConfig(pCan_ctrl->pCANx, pNode->rxMb, NULL, false); //释放邮箱
            aos_free(pNode->mb_rx_transfer.frame);                              //释放节点frame内存
            aos_free(pNode);                                                    //释放链表节点内存
        }
    }
    aos_mutex_unlock(&pCan_ctrl->mutex);
    return true;
err_1:
    return false;
}
/**
 * @brief       发送SDO数据包
 * @param[in]	port_id             can 端口索引
 * @param[in]	node_id             发送节点 id
 * @param[in]	cmd                 cmd 字段
 * @param[in]	index               index 字段
 * @param[in]	data                数据字段
 * @return      bool                发送结果
 */
 bool can_control_send_sdo_frame(uint8_t port_id, uint32_t node_id, uint8_t cmd, uint16_t index, uint8_t subindex, uint32_t data)
{
    flexcan_frame_t frame;
    frame.id = FLEXCAN_ID_STD(node_id);
    frame.length = 0x08;
    frame.format = kFLEXCAN_FrameFormatStandard;
    frame.type = kFLEXCAN_FrameTypeData;
    frame.dataByte0 = cmd;
    frame.dataByte1 = index;
    frame.dataByte2 = index >> 8;
    frame.dataByte3 = subindex;

    frame.dataWord1 = data;
    
    return _can_control_send(port_id, &frame);
}



// 内部函数
/************************************************************************/
/**
 * @brief       获取剩余可用接收邮箱序号
 * @param[in]	pCANx               CAN handle
 * @return      int8_t              剩余可用的邮箱编号，-1表示无可用
 */
static int8_t _get_free_rx_mb(CAN_Type *pCANx)
{
	uint8_t ret = 0;
    for (uint8_t i = RX_MESSAGE_BOX_OFFSET; i < MAX_RX_MESSAGE_BOX_NUM; i++)
    {
        if (0 == pCANx->MB[i].CS){
			return i;
		}
    }
    return -1;
}
/**
 * @brief       获取剩余可用接收邮箱数量
 * @param[in]	pCANx               CAN handle
 * @return      uint8_t             剩余可用接收邮箱数量
 */
static uint8_t _get_rx_mb_remaining_nums(CAN_Type *pCANx)
{
	uint8_t ret = 0;
    for (uint8_t i = RX_MESSAGE_BOX_OFFSET; i < MAX_RX_MESSAGE_BOX_NUM; i++)
    {
        if (0 == pCANx->MB[i].CS){
			ret++;
		}
    }
    return ret;
}
/**
 * @brief       通过端口id获取Type_CAN_Manage_Def 句柄
 * @param[in]	port_id                 索引 id
 * @return      can_controller_t*    can_controller_t 句柄
 */
static can_controller_t *_get_can_controller_handler_byId(uint8_t port_id)
{
    if (port_id < sizeof(can_ctrl) / sizeof(can_ctrl[0])){
        return &can_ctrl[port_id];
    }else{
        return NULL;
    }
}

/**
 * @brief       can 发送接口
 * @param[in]	port_id             can 端口索引
 * @param[in]	pFrame              数据包结构
 * @return      bool                发送结果
 */
static bool _can_control_send(uint8_t port_id, flexcan_frame_t * const pFrame)
{
    if(g_tx_cnts++ > 0x8FFFFFFF){
        g_tx_cnts = g_tx_cnts >> 8;
        g_tx_fail_cnts = g_tx_fail_cnts >> 8;
    }
    can_controller_t *pCan_ctrl = _get_can_controller_handler_byId(port_id);
    CHECK_NULL(pCan_ctrl, "port_id error", err_1);
#if 0   // 非阻塞发送
    flexcan_mb_transfer_t mb_tx_transfer;
    mb_tx_transfer.frame = pFrame;
    mb_tx_transfer.mbIdx = TX_MESSAGE_BOX_OFFSET;
    uint8_t retryCnt = 10;
    while(retryCnt--){
        if (kStatus_Success == FLEXCAN_TransferSendNonBlocking(pCan_ctrl->pCANx, &pCan_ctrl->flexcanHandle, &mb_tx_transfer)){
            return true;
        }
    }
#else   // 阻塞发送
    if (kStatus_Success == FLEXCAN_TransferSendBlocking(pCan_ctrl->pCANx, TX_MESSAGE_BOX_OFFSET, pFrame)) {
        return true;
    }
#endif
err_1:
    g_tx_fail_cnts++;
    return false;
}
/**
 * @brief       CAN中断回调
 * @param[in]	base                CAN handler
 * @param[in]	handle              FlexCAN handle
 * @param[in]	status              回调事件类型
 * @param[in]	result              接收的消息邮箱编号
 * @param[in]	userData            用户数据，注册时传入了 can_controller handle
 */
static void _flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData)
{
    rx_node_t *pNode = NULL;
	slist_t *cur = NULL;

    can_controller_t *pCan_ctrl = (can_controller_t *)userData;
    if (NULL == pCan_ctrl){
        return;
    }

    switch (status)
    {
        case kStatus_FLEXCAN_RxIdle:
            slist_for_each_entry_safe(&pCan_ctrl->list_Mb, cur, pNode, rx_node_t, next) {
                if (pNode->rxMb == result)
                    break;
            }
            if (NULL != pNode){
                aos_queue_send(pNode->rx_queue, pNode->mb_rx_transfer.frame, sizeof(flexcan_frame_t));
                FLEXCAN_TransferReceiveNonBlocking(base, handle, &pNode->mb_rx_transfer);
            }
            break;

        case kStatus_FLEXCAN_TxIdle:

            break;
            
        case kStatus_FLEXCAN_RxOverflow:
            isFlexCanRxOverflow = true;
            break;

        case kStatus_FLEXCAN_WakeUp:
            //唤醒状态未使能
            break;

        default:
            printf("interupt error: 0x%08X", (int)status);
            break;
    }
}


